﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Autodesk.AutoCAD.Windows.Features.PointCloud.PointCloudColorMapping
{

    public struct ColorRange
    {
        public double RangeStart;
        public double RangeEnd;
        public Color RangeColor;
    }

    public partial class ColorRamp : UserControl
    {

        public static DependencyProperty NumColorsProperty;
        public static DependencyProperty IsGradientProperty;
        public static DependencyProperty UserIsGradientProperty;
        public static DependencyProperty DisplayModeProperty;
        public static DependencyProperty MaxColorProperty;
        public static DependencyProperty MinColorProperty;
        public static DependencyProperty MaxRangeValueProperty;
        public static DependencyProperty MinRangeValueProperty;
        public static DependencyProperty ColorsProperty;
        public static DependencyProperty ShowPercentProperty;

        Grid grid;

        public List<ColorRange> RangeList = new List<ColorRange>() { new ColorRange(),new ColorRange() };

        public enum RampType { kElevation, kIntensity, kClassification };

        static ColorRamp()
        {
            NumColorsProperty = DependencyProperty.Register("NumColors", typeof(int), typeof(ColorRamp), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnNumColorsChanged)));
            IsGradientProperty = DependencyProperty.Register("IsGradient", typeof(bool), typeof(ColorRamp), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsGradientChanged)));
            UserIsGradientProperty = DependencyProperty.Register("UserIsGradient", typeof(bool), typeof(ColorRamp), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnUserIsGradientChanged)));
            DisplayModeProperty = DependencyProperty.Register("DisplayMode", typeof(RampType), typeof(ColorRamp), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDisplayModeChanged)));
            MaxColorProperty = DependencyProperty.Register("MaxColor", typeof(Color), typeof(ColorRamp), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnMaxColorChanged)));
            MinColorProperty = DependencyProperty.Register("MinColor", typeof(Color), typeof(ColorRamp), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnMinColorChanged)));
            MaxRangeValueProperty = DependencyProperty.Register("MaxRangeValue", typeof(double), typeof(ColorRamp), new FrameworkPropertyMetadata(100.0,new PropertyChangedCallback(OnMaxRangeValueChanged)));
            MinRangeValueProperty = DependencyProperty.Register("MinRangeValue", typeof(double), typeof(ColorRamp), new FrameworkPropertyMetadata(0.0,new PropertyChangedCallback(OnMinRangeValueChanged)));
            ColorsProperty = DependencyProperty.Register("Colors", typeof(Color[]), typeof(ColorRamp), new FrameworkPropertyMetadata(null,FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,new PropertyChangedCallback(OnColorsChanged)));
            ShowPercentProperty = DependencyProperty.Register("ShowPercent", typeof(bool), typeof(ColorRamp), new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnMaxRangeValueChanged)));
        }

        public ColorRamp()
        {
            Init();
        }

        protected void Init()
        {
            
            grid = new Grid();

            AddChild(grid);
            this.Focusable = true;

        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Some methods to manipulate the color list
        /// </summary>
        public void AddListItem(ColorRange range, int AtIndex = -1)
        {
            if (AtIndex < 0 || AtIndex > RangeList.Count())
            {
                RangeList.Add(range);
            }
            else
            {
                RangeList.Insert(AtIndex, range);
            }
        }

        public void ReplaceColor(Color color, int AtIndex)
        {
            if (AtIndex < 0 || AtIndex > RangeList.Count())
            {
               return;
            }
            else
            {
                ColorRange range = RangeList[AtIndex];
                range.RangeColor = color;
                RangeList[AtIndex] = range;
                UpdateRamp();
            }
        }

        public void ReplaceColorList( List<ColorRange> NewList )
        {
            ClearColorList();
            RangeList = NewList;
            Colors = RangeList.Select(oo => oo.RangeColor).ToArray();
        }

        public void ClearColorList()
        {
            RangeList.Clear();
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Set up the ramp based on the current data and dialog state
        /// </summary>
        public void UpdateRamp()
        {
            if (RangeList == null)
                return;
            RemoveRamp();
            if (IsGradient)
                SetRampGradient();
            else
                SetRampSegmented();
            //Set all of our ramp-related properties
            if (RangeList.Count > 0)
            {
                MaxColor = RangeList[0].RangeColor;
                MinColor = RangeList[RangeList.Count - 1].RangeColor;
                //MaxRangeValue = RangeList[0].RangeEnd;
                //MinRangeValue = RangeList[RangeList.Count - 1].RangeStart;
            }
        }

        protected void SetRampGradient()
        {
            Rectangle rect = new Rectangle();
            rect.Width = Width;
            rect.Height = Height;
            for (int q = 0; q < RangeList.Count; q++)
            {
                RowDefinition row = new RowDefinition();
                grid.RowDefinitions.Add(row);
                ColorRange range = RangeList[q];
                FindNewRangeValues(ref range, q);
            }
            LinearGradientBrush GradientFill = new LinearGradientBrush();

            GradientFill.StartPoint = new Point(0.5, 0);
            GradientFill.EndPoint = new Point(0.5, 1);

            GradientFill.GradientStops.Clear();

            if (RangeList.Count - 1 == 0)
                return;
            double nstep = (double)1 / (double)(RangeList.Count - 1);
            double place = 0;
            for (int i = 0; i < RangeList.Count; i++)
            {
                GradientFill.GradientStops.Add(
                    new GradientStop((Color)RangeList[i].RangeColor, place));
                place += nstep;

                //Also set up individual Rectangles
                Rectangle subRect = new Rectangle();
                subRect.Width = Width;
                subRect.Height = Height / (double)NumColors;
                //Add the event handlers for the rectangles...
                subRect.AddHandler(Rectangle.MouseEnterEvent, new RoutedEventHandler(OnRectangleMouseEnter), true);
                subRect.AddHandler(Rectangle.MouseLeaveEvent, new RoutedEventHandler(OnRectangleMouseLeave), true);
                subRect.AddHandler(Rectangle.MouseLeftButtonDownEvent, new RoutedEventHandler(OnRectangleMouseLeftButtonDown), true);
                ContextMenuService.SetContextMenu(subRect, GetMenu(subRect));
                SolidColorBrush brush = new SolidColorBrush(RangeList[i].RangeColor);
                subRect.Fill = brush;
                Grid.SetRow(subRect, i);
                Grid.SetZIndex(subRect, 1);
                grid.Children.Add(subRect);

                //also add in the range labels...
                //also add in the range labels...
                if (DisplayMode != RampType.kClassification)
                {
                    Label label = new Label();
                    SolidColorBrush WhiteBrush = new SolidColorBrush(System.Windows.Media.Colors.White);
                    SolidColorBrush GrayBrush = new SolidColorBrush(System.Windows.Media.Colors.Gray);
                    if (i == 0)
                    {
                        Label labelEnd = new Label();
                        labelEnd.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                        double d = Math.Round(RangeList[i].RangeEnd, 2);
                        labelEnd.Content = Label(d);
                        labelEnd.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
                        labelEnd.Background = GrayBrush;
                        labelEnd.Foreground = WhiteBrush;
                        labelEnd.Padding = LabelPadding;
                        Grid.SetRow(labelEnd, i);
                        Grid.SetZIndex(labelEnd, 3);
                        labelEnd.IsHitTestVisible = false;
                        
                        grid.Children.Add(labelEnd);
                    }
                    else if (i == RangeList.Count - 1)
                    {
                        Label labelStart = new Label();
                        labelStart.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
                        double d = Math.Round(RangeList[i].RangeStart, 2);
                        labelStart.Content = Label(d);
                        labelStart.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
                        labelStart.Background = GrayBrush;
                        labelStart.Foreground = WhiteBrush;
                        labelStart.Padding = LabelPadding;
                        Grid.SetRow(labelStart, i);
                        Grid.SetZIndex(labelStart, 3);
                        labelStart.IsHitTestVisible = false; 
                        grid.Children.Add(labelStart);

                    }
                    else if (i > 0)
                    {
                        //for this mode, we want labels at the lines between segments
                        label.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                        double d = Math.Round((RangeList[i].RangeStart + RangeList[i].RangeEnd)/2.0, 2);
                        label.Content = Label(d);
                        label.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
                        label.Background = GrayBrush;
                        label.Foreground = WhiteBrush;
                        label.Padding = LabelPadding;
                        Grid.SetRow(label, i);
                        Grid.SetRowSpan(label, 1);
                        Grid.SetZIndex(label, 3);
                        label.IsHitTestVisible = false; 
                        grid.Children.Add(label);
                    }
                }
            }
            rect.Fill = GradientFill;
            Grid.SetRowSpan(rect, RangeList.Count);
            Grid.SetZIndex(rect, 2);
            rect.IsHitTestVisible = false;
            grid.Children.Add(rect);
            rect.UpdateLayout();
        }
        private string Label(double v)
        {
            if ((bool)this.GetValue(ShowPercentProperty))
                return v.ToString("#0") + "%";
            else
                return UnitUtils.DoubleToString(v);
        }
        protected void SetRampSegmented()
        {
            Color color1;
            for (int q = 0; q < RangeList.Count; q++)
            {
                RowDefinition row = new RowDefinition();
                grid.RowDefinitions.Add(row);
                ColorRange range = RangeList[q];
                FindNewRangeValues(ref range, q);
            }
            for (int i = 0; i < RangeList.Count; i++)
            {
                color1 = RangeList[i].RangeColor;
                Rectangle rect = new Rectangle();
                rect.Width = Width;
                rect.Height = Height/(double)NumColors;
                //Add the event handlers for the rectangles...
                rect.AddHandler(Rectangle.MouseEnterEvent, new RoutedEventHandler(OnRectangleMouseEnter), true);
                rect.AddHandler(Rectangle.MouseLeaveEvent, new RoutedEventHandler(OnRectangleMouseLeave), true);
                rect.AddHandler(Rectangle.MouseLeftButtonDownEvent, new RoutedEventHandler(OnRectangleMouseLeftButtonDown), true);
                ContextMenuService.SetContextMenu(rect, GetMenu(rect));
                SolidColorBrush brush = new SolidColorBrush(color1);
                rect.Fill = brush;
                Grid.SetRow(rect, i);
                Grid.SetZIndex(rect, 1); 
                grid.Children.Add(rect);

                //also add in the range labels...
                if (DisplayMode != RampType.kClassification)
                {
                    Label label = new Label();
                    SolidColorBrush WhiteBrush = new SolidColorBrush(System.Windows.Media.Colors.White);
                    SolidColorBrush GrayBrush = new SolidColorBrush(System.Windows.Media.Colors.Gray);
                    if (i == 0)
                    {
                        Label labelEnd = new Label();
                        labelEnd.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                        double d = Math.Round(RangeList[i].RangeEnd, 2);
                        labelEnd.Content = Label(d);
                        labelEnd.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
                        labelEnd.Background = GrayBrush;
                        labelEnd.Foreground = WhiteBrush;
                        labelEnd.Padding = LabelPadding;
                        Grid.SetRow(labelEnd, i);
                        Grid.SetZIndex(labelEnd, 3);
                        labelEnd.IsHitTestVisible = false; 
                        grid.Children.Add(labelEnd);
                    }
                    else if (i == RangeList.Count - 1)
                    {
                        Label labelStart = new Label();
                        labelStart.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
                        double d = Math.Round(RangeList[i].RangeStart, 2);
                        labelStart.Content = Label(d);
                        labelStart.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
                        labelStart.Background = GrayBrush;
                        labelStart.Foreground = WhiteBrush;
                        labelStart.Padding = LabelPadding;
                        Grid.SetRow(labelStart, i);
                        Grid.SetZIndex(labelStart, 3);
                        labelStart.IsHitTestVisible = false; 
                        grid.Children.Add(labelStart);

                    }
                    if (i > 0)
                    {
                        //for this mode, we want labels at the lines between segments
                        label.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                        double d = Math.Round(RangeList[i].RangeEnd, 2);
                        label.Content = Label(d);
                        label.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
                        label.Background = GrayBrush;
                        label.Foreground = WhiteBrush;
                        label.Padding = LabelPadding;
                        Grid.SetRow(label, i - 1);
                        Grid.SetRowSpan(label, 2);
                        Grid.SetZIndex(label, 3);
                        label.IsHitTestVisible = false; 
                        grid.Children.Add(label);
                    }
                }
                
            }

        }
        static Thickness LabelPadding = new Thickness(5.0,1.0,5.0,1.0);
        protected void RemoveRamp()
        {
            grid.Children.Clear();
            grid.RowDefinitions.Clear();
            grid.ColumnDefinitions.Clear();
        }

        //This method is used when the number of colors in the Ramp is changed. We want to try to keep the ramp looking almost the same, but using more or fewer colors accordingly.
        public void RedistributeColors()
        {
            if( RangeList == null || RangeList.Count == 0)
                return;
            int CurrentNum = RangeList.Count;
            List<ColorRange> newList = new List<ColorRange>();
            //always add the first
            ColorRange rangeFirst = RangeList[0];
            FindNewRangeValues(ref rangeFirst, 0);
            newList.Add(rangeFirst);

            //first we need the number of colors we'll need between first and last (we always add those)
            int nWantedLess1 = NumColors - 1;
            int nHaveLess1 = CurrentNum - 1;
            //then we figure a ratio to divide the current colors by new colors
            if (nWantedLess1 != 0)
            {

                double dStep = (double)nHaveLess1 / (double)(nWantedLess1);
                double counter = 0.0;
                int nCount = 0;
                for (int i = 0; i < (nWantedLess1 -1); i++)
                {
                    counter += dStep;
                    nCount = (int)counter;
                    if (counter == (double)nCount)
                    {
                        //we still may need to adjust the range
                        ColorRange range = RangeList[nCount];
                        FindNewRangeValues(ref range, newList.Count);
                        newList.Add(range);
                    }
                    else
                    {
                        ColorRange range = new ColorRange();
                        int nIndex = nCount;
                        double pct = counter - (double)nCount;
                        range.RangeColor = FindColorBetween(RangeList[nIndex].RangeColor, RangeList[nIndex + 1].RangeColor, pct);
                        FindNewRangeValues(ref range, newList.Count);
                        newList.Add(range);
                    }
                }
            }
            //always add the last item
            ColorRange rangeLast = RangeList[RangeList.Count - 1];
            FindNewRangeValues(ref rangeLast, newList.Count);
            newList.Add(rangeLast);
            ReplaceColorList(newList);
            UpdateRamp();
        }

        protected void FindNewRangeValues(ref ColorRange range, int nAtIndex)
        {
            double dTotalRange = 0.0;
            double dEachRange = 0.0;
            double dNewStart = 0.0;
            double dNewEnd = 0.0;
            int nReverse = RangeList.Count - nAtIndex - 1;

            dTotalRange = MaxRangeValue - MinRangeValue;
            dEachRange = dTotalRange / (double)RangeList.Count;
            dNewStart = MinRangeValue + (dEachRange * (double)nReverse);
            dNewEnd = dNewStart + dEachRange;

            if (nAtIndex == 0)
                dNewEnd = MaxRangeValue;

            range.RangeStart = dNewStart;
            range.RangeEnd = dNewEnd;
        }

        public void RebalanceRanges()
        {//call this when the range values change to redistribute the range values
            for (int i = 0; i < RangeList.Count; i++)
            {
                ColorRange range = RangeList[i];
                FindNewRangeValues(ref range, i);
                RangeList[i] = range;
            }
        }

        protected Color FindColorBetween(Color color1, Color color2, double pct = .5)
        {
            Color MidColor = new Color();
            //SolidColorBrush Brush1 = new SolidColorBrush(color1);
            //SolidColorBrush Brush2 = new SolidColorBrush(color2);
            //SolidColorBrush BrushMid = new SolidColorBrush();


            int c1R = (int)color1.R;
            int c1G = (int)color1.G;
            int c1B = (int)color1.B;

            int c2R = (int)color2.R;
            int c2G = (int)color2.G;
            int c2B = (int)color2.B;

            int c3R = 0;
            if (c1R > c2R)
            {
                c3R = c1R - (int)((c1R - c2R) *pct);
            }
            else
            {
                c3R = (int)((c2R - c1R) * pct) + c1R;
            }

            int c3G = 0;
            if (c1G > c2G)
            {
                c3G = c1G - (int)((c1G - c2G) * pct);
            }
            else
            {
                c3G = (int)((c2G - c1G) * pct) + c1G;
            }

            int c3B = 0;
            if (c1B > c2B)
            {
                c3B = c1B - (int)((c1B - c2B) * pct);
            }
            else
            {
                c3B = (int)((c2B - c1B) * pct) + c1B;
            }

            MidColor = Color.FromRgb( (byte)c3R, (byte)c3G, (byte)c3B);

            return MidColor;
        }

        public void SelectColor(int nIndex, int delta = 0)
        {
            Color? wpfColor = RangeList[nIndex].RangeColor;
            wpfColor = ColorSelector.SelectColor(wpfColor);
            if (null != wpfColor)
            {
                ColorRange range = RangeList[nIndex];
                range.RangeColor = wpfColor.GetValueOrDefault();

                List<ColorRange> nrange = new List<ColorRange>(RangeList);
                if (delta > 0 && RangeList.Count < Ramp.intervals[Ramp.intervals.Length - 1]) 
                {
                    nrange.Insert(nIndex, range);
                    nrange[nIndex] = range;
                }
                else if (delta == 0 )
                {
                    nrange[nIndex] = range;
                }
                else if (delta < 0 && RangeList.Count > Ramp.intervals[0]) nrange.RemoveAt(nIndex);
                
                Colors = nrange.Select(oo => oo.RangeColor).ToArray();
            }
        }

        public Color GetColorAt(int nIndex)
        {
            if (RangeList == null || nIndex > RangeList.Count || nIndex < 0)
                return new Color();
            Color clr = RangeList[nIndex].RangeColor;

            return clr;
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// These are event handler overrides for the color ramp as a whole.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);
            //if (DisplayMode == RampType.kClassification)
            //{
            //    UserIsGradient = false;
            //    NumColors++;
            //    NumColors--;
            //}
            //    //revert back to what we were
            //    IsGradient = UserIsGradient;
            //    UpdateRamp();
            //}
        }
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);
            //if (DisplayMode == RampType.kClassification)
            //{
            //    UserIsGradient = false;
            //}
            //    if (IsGradient)
            //    {
            //        IsGradient = false;
            //        UpdateRamp();
            //    }
            //}
            
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// These are event handlers for the color band rectangles 
        /// </summary>
        protected void OnRectangleMouseEnter( Object sender, RoutedEventArgs e )
        {
            if (DisplayMode != RampType.kClassification)
            {
                Rectangle rect = (Rectangle)sender;
                rect.StrokeThickness = 3;
                SolidColorBrush blackBrush = new SolidColorBrush();
                blackBrush.Color = System.Windows.Media.Colors.Black;
                rect.Stroke = blackBrush;
                Grid.SetZIndex(rect, 3);
                //rect.Visibility = Visibility.Visible;
            }

        }

        protected void OnRectangleMouseLeave(Object sender, RoutedEventArgs e)
        {
            if (DisplayMode != RampType.kClassification)
            {
                Rectangle rect = (Rectangle)sender;
                rect.StrokeThickness = 0;
                SolidColorBrush TransparentBrush = new SolidColorBrush();
                TransparentBrush.Color = System.Windows.Media.Colors.Transparent;
                rect.Stroke = TransparentBrush;
                if (UserIsGradient)
                    Grid.SetZIndex(rect, 1);
            }
        }

        protected void OnRectangleMouseLeftButtonDown(Object sender, RoutedEventArgs e)
        {
            if (DisplayMode != RampType.kClassification)
            {
                Rectangle rect = (Rectangle)sender;
                int nRow = Grid.GetRow(rect);
                SelectColor(nRow);
            }
        }
        /////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// These are accessors for our properties
        /// </summary>
        public int NumColors
        {
            get
            {
                return (int)GetValue(NumColorsProperty);
            }

            set
            {
                if (value > 1)
                    SetValue(NumColorsProperty, value);
            }
        }

        public bool IsGradient
        {
            get
            {
                return (bool)GetValue(IsGradientProperty);
            }

            set
            {
                SetValue(IsGradientProperty, value);
            }
        }

        public bool UserIsGradient
        {
            get
            {
                return (bool)GetValue(UserIsGradientProperty);
            }

            set
            {
                SetValue(UserIsGradientProperty, value);
                SetValue(IsGradientProperty, value);
                UpdateRamp();
            }
        }

        public RampType DisplayMode
        {
            get
            {
                return (RampType)GetValue(DisplayModeProperty);
            }

            set
            {
                SetValue(DisplayModeProperty, value);
            }
        }

        public Color MaxColor
        {
            get
            {
                return (Color)GetValue(MaxColorProperty);
            }

            set
            {
                SetValue(MaxColorProperty, value);
            }
        }

        public Color MinColor
        {
            get
            {
                return (Color)GetValue(MinColorProperty);
            }

            set
            {
                SetValue(MinColorProperty, value);
            }
        }
        public double MaxRangeValue
        {
            get
            {
                return (double)GetValue(MaxRangeValueProperty);
            }

            set
            {
                SetValue(MaxRangeValueProperty, value);
            }
        }

        public double MinRangeValue
        {
            get
            {
                return (double)GetValue(MinRangeValueProperty);
            }

            set
            {
                SetValue(MinRangeValueProperty, value);
            }
        }
        public Color[] Colors
        {
            get
            {
                return (Color[])GetValue(ColorsProperty);
            }

            set
            {
                SetValue(ColorsProperty, value);
            }
        }
        public bool ShowPercent
        {
            get
            {
                return (bool)GetValue(ShowPercentProperty);
            }

            set
            {
                SetValue(ShowPercentProperty, value);
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Event handlers for when our properties are changed
        /// </summary>
        private static void OnNumColorsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender == null)
                return;
            ColorRamp c = (ColorRamp)sender;

            if ((int)e.NewValue != c.RangeList.Count)
            {
                c.RedistributeColors();
            }
        }

        private static void OnIsGradientChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        private static void OnColorListChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        private static void OnUserIsGradientChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender == null)
                return;
            ColorRamp c = (ColorRamp)sender;
            c.IsGradient = c.UserIsGradient;
            c.UpdateRamp();

        }
        private static void OnDisplayModeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        private static void OnMaxColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        private static void OnMinColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        private static void OnMaxRangeValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender == null)
                return;
            ColorRamp c = (ColorRamp)sender;
            c.RebalanceRanges();
            c.UpdateRamp();

        }
        private static void OnMinRangeValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender == null)
                return;
            ColorRamp c = (ColorRamp)sender;
            c.RebalanceRanges();
            c.UpdateRamp();

        }
        private static void OnColorsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender == null)
                return;
            ColorRamp c = (ColorRamp)sender;

            var cols = e.NewValue as Color[];
            if (cols == null || cols.Length < 2)
            {
                c.RangeList.Clear();
                c.RemoveRamp();
                c.MaxColor = c.MinColor = new Color();
                c.IsGradient = false;
                return;
            }
            c.RangeList.Clear();
            foreach (var item in cols)
            {
                c.RangeList.Add(new ColorRange() { RangeColor = item });
            }
            c.RebalanceRanges();
            c.UpdateRamp();
        }
        public void MenuClick(Object sender,RoutedEventArgs e)
        {
            var mi = sender as System.Windows.Controls.MenuItem;
            var head = mi.Header as string;
            Rectangle rect = (Rectangle)mi.Tag;
            int nRow = Grid.GetRow(rect);

            switch (menu_items.IndexOf(head))
            {
                case 0:
                    SelectColor(nRow);
                    break;
                case 1:
                    SelectColor(nRow, 1);
                    break;
                case 2:
                    var nrange = new List<ColorRange>(RangeList);
                    if (RangeList.Count > Ramp.intervals[0]) nrange.RemoveAt(nRow);
                    Colors = nrange.Select(oo => oo.RangeColor).ToArray();
                    break;
                case 3:
                    Colors = RangeList.Select(oo => oo.RangeColor).Reverse().ToArray();
                    break;
                case 4:
                    var n = RangeList.Count;
                    NumColors = 2;
                    NumColors = n;
                    break;
            }
        }

        List<string> menu_items = new List<string>()        {
            Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.EditColor,
            Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.AddColor,
            Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.DeleteColor,
            Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.ReverseColorOrder,
            Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.RerampColors
        };
        private ContextMenu GetMenu(Object o)
        {
            var cmenu = new ContextMenu();
            foreach (var item in menu_items)
            {
                var mi = new System.Windows.Controls.MenuItem { Header = item, Tag = o };
                if (menu_items.IndexOf(item) == 1) mi.IsEnabled = (RangeList.Count < Ramp.intervals[Ramp.intervals.Length - 1]);
                else if (menu_items.IndexOf(item) == 2) mi.IsEnabled = (RangeList.Count > Ramp.intervals[0]);
                mi.Click += MenuClick;
                cmenu.Items.Add(mi);
            }
            return cmenu;
        }
        public void ChangeColorLast()
        {
            SelectColor(RangeList.Count-1);
        }
    }
}
